#include "VulkanApplication.h"
#include <vector>
#include <iostream>

int main(int argc, char** argv)
{
    VulkanApplication app("c04_swapchain", 1024, 768);
    if (!app.initialized())
    {
        printf("Failed to initialize VulkanApplication.\n");
        return 1;
    }

    // Get capabilities
    VkSurfaceCapabilitiesKHR caps;
    VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
        app.getPhysicalDevice(), app.getSurface(), &caps);
    if (result != VK_SUCCESS)
    {
        printf("Failed to get surface capabilities.\n");
        return 1;
    }

    uint32_t formatCount = 0, presentModeCount = 0;
    result = vkGetPhysicalDeviceSurfaceFormatsKHR(
        app.getPhysicalDevice(), app.getSurface(), &formatCount, nullptr);
    if (result != VK_SUCCESS || formatCount == 0)
    {
        printf("Failed to get surface formats.\n");
        return 1;
    }

    result = vkGetPhysicalDeviceSurfacePresentModesKHR(
        app.getPhysicalDevice(), app.getSurface(), &presentModeCount, nullptr);
    if (result != VK_SUCCESS || presentModeCount == 0)
    {
        printf("Failed to get surface present modes.\n");
        return 1;
    }

    uint32_t formatIndex = 0, presentModeIndex = 0;
    std::vector<VkSurfaceFormatKHR> formats(formatCount);
    std::vector<VkPresentModeKHR> presentModes(presentModeCount);

    vkGetPhysicalDeviceSurfaceFormatsKHR(
        app.getPhysicalDevice(), app.getSurface(), &formatCount, formats.data());
    for (uint32_t i = 0; i < formatCount; ++i)
    {
        //printf("Surface format / colorspace: %d / %d\n", formats[i].format, formats[i].colorSpace);
        if (formats[i].format == VK_FORMAT_B8G8R8A8_SRGB &&
            formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) formatIndex = i;
    }

    vkGetPhysicalDeviceSurfacePresentModesKHR(
        app.getPhysicalDevice(), app.getSurface(), &presentModeCount, presentModes.data());
    for (uint32_t i = 0; i < presentModeCount; ++i)
    {
        //printf("Surface present mode: %d\n", presentModes[i]);
        if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) presentModeIndex = i;
    }

    printf("Image extent: %d x %d; ImageCount: [%d, %d]; Format: %d; Present mode: %d\n",
           caps.maxImageExtent.width, caps.maxImageExtent.height,
           caps.minImageCount, caps.maxImageCount,
           formats[formatIndex].format, presentModes[presentModeIndex]);

    // Create swap chain
    VkSwapchainCreateInfoKHR createInfo
    {
        VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
        nullptr, 0,
        app.getSurface(),
        (caps.minImageCount + caps.maxImageCount) / 2,
        formats[formatIndex].format,
        formats[formatIndex].colorSpace,
        caps.maxImageExtent,
        1,  // imageArrayLayers
        VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,  // imageUsage
        VK_SHARING_MODE_EXCLUSIVE,  // imageSharingMode
        0, nullptr,  // queueFamilyIndex
        caps.currentTransform,
        VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,  // compositeAlpha
        presentModes[presentModeIndex],
        VK_TRUE,
        nullptr
    };

    VkSwapchainKHR swapChain = nullptr;
    result = vkCreateSwapchainKHR(app.getDevice(), &createInfo, nullptr, &swapChain);
    if (result != VK_SUCCESS)
    {
        printf("Failed to create swap chain.\n");
        return 1;
    }

    uint32_t imageCount = 0;
    vkGetSwapchainImagesKHR(app.getDevice(), swapChain, &imageCount, nullptr);

    std::vector<VkImage> swapChainImages(imageCount);
    vkGetSwapchainImagesKHR(app.getDevice(), swapChain, &imageCount, swapChainImages.data());

    printf("Swap chain %p, images: %d\n", swapChain, imageCount);
    // TODO

    // Main loop
    while (!app.shouldClose())
    {
        glfwPollEvents();
    }

    if (swapChain != nullptr) vkDestroySwapchainKHR(app.getDevice(), swapChain, nullptr);
    return 0;
}